<template>
  <div class="dashboard-container">
    <!-- 侧边栏开关按钮 -->
    <button 
      class="sidebar-toggle-btn btn btn-primary fixed-top mt-3 ms-3 z-50"
      @click="toggleSidebar"
      :class="{ 'open': sidebarOpen }"
    >
      <i :class="sidebarOpen ? 'bi bi-x' : 'bi bi-sliders'" style="font-size: 1.25rem;"></i>
    </button>
    
    <!-- 配置管理侧边栏 -->
    <div class="config-sidebar" :class="{ 'open': sidebarOpen }">
      <div class="sidebar-header">
        <h3 class="text-center mb-0">配置管理</h3>
      </div>
      <div class="sidebar-content">
        <ConfigManager ref="configManagerRef" />
      </div>
    </div>
    
    <div class="main-content" :class="{ 'sidebar-open': sidebarOpen }">
      <div class="row">
        <div class="col-12">
          <h1 class="text-center mb-4">livetalking-v15数字人交互平台</h1>
        </div>
      </div>

    <div class="row">
      <!-- 视频区域 -->
      <div class="col-lg-8">
        <div class="card">
          <div class="card-header d-flex justify-content-between align-items-center">
            <div>
              <span class="status-indicator" :class="statusClass"></span>
              <span>{{ statusText }}</span>
            </div>
          </div>
          <div class="card-body p-0">
            <div class="video-container">
              <video id="video" autoplay muted playsinline></video>
              <audio id="audio" autoplay playsinline style="display: none;"></audio>
              <div class="recording-indicator" id="recording-indicator">
                <div class="blink"></div>
                <span>录制中</span>
              </div>
            </div>
            
            <div class="controls-container">
              <div class="row">
                <div class="col-md-6 mb-3">
                  <button 
                    v-if="!isConnected"
                    class="btn btn-primary w-100"
                    id="btn_start_connection"
                    @click="startConnection"
                    :disabled="isConnecting"
                  >
                    <i class="bi bi-play-fill"></i> 开始连接
                  </button>
                  <button 
                    v-else
                    class="btn btn-danger w-100"
                    @click="stopConnection"
                  >
                    <i class="bi bi-stop-fill"></i> 停止连接
                  </button>
                  
                  <!-- STUN服务器选择框 - 仅在未连接时显示 -->
                  <div v-if="!isConnected" class="form-check mt-2">
                    <input 
                      class="form-check-input" 
                      type="checkbox" 
                      id="useStunCheckbox"
                      v-model="useStunServer"
                      @change="handleStunChange"
                    >
                    <label class="form-check-label" for="useStunCheckbox">
                      使用STUN服务器
                    </label>
                  </div>
                </div>
                <div class="col-md-6 mb-3">
                  <div class="d-flex flex-column gap-2">
                    <button 
                      :class="['btn', 'w-100', isRecording ? 'btn-danger' : 'btn-outline-primary']"
                      id="btn_toggle_record"
                      @click="toggleRecording"
                      :disabled="!isConnected"
                    >
                      <i :class="isRecording ? 'bi bi-stop-fill' : 'bi bi-record-fill'"></i> 
                      {{ isRecording ? '停止录制' : '开始录制' }}
                    </button>
                    
                    <!-- 下载录制文件按钮 - 仅在有录制文件时显示 -->
                    <button 
                      v-if="recordingFileUrl"
                      class="btn btn-outline-success w-100"
                      id="btn_download_recording"
                      @click="downloadRecording"
                      :disabled="isDownloading"
                    >
                      <i class="bi bi-download"></i> {{ isDownloading ? '正在尝试下载...' : '下载录制文件' }}
                    </button>
                    
                    <!-- 下载状态指示器 -->
                    <div v-if="isDownloading" class="alert alert-info p-2 text-sm">
                      <i class="bi bi-spinner bi-spin"></i> 正在测试并尝试不同的下载链接...
                    </div>
                    
                    <!-- 下载错误提示 -->
                    <div v-if="downloadError" class="alert alert-danger p-2 text-sm">
                      <i class="bi bi-exclamation-circle"></i> {{ downloadError }}
                      <button class="btn btn-link p-0 m-0 text-xs ms-2" @click="copySessionInfo">复制会话信息</button>
                    </div>
                  </div>
                </div>
              </div>

              <div class="row">
                <div class="col-12">
                  <div class="video-size-control">
                    <label for="video-size-slider" class="form-label">视频大小调节: <span id="video-size-value">{{ videoSize }}%</span></label>
                    <input type="range" class="form-range" id="video-size-slider" min="50" max="150" v-model="videoSize">
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧交互 -->
      <div class="col-lg-4">
        <div class="card">
          <div class="card-header">
            <ul class="nav nav-tabs card-header-tabs" id="interaction-tabs" role="tablist">
              <li class="nav-item" role="presentation">
                <button 
                  class="nav-link" 
                  :class="{active: activeTab === 'chat'}"
                  @click="activeTab = 'chat'"
                >对话模式</button>
              </li>
              <li class="nav-item" role="presentation">
                <button 
                  class="nav-link" 
                  :class="{active: activeTab === 'tts'}"
                  @click="activeTab = 'tts'"
                >朗读模式</button>
              </li>

            </ul>
          </div>
          <div class="card-body">
            <!-- 对话面板 - 移到条件渲染外以保持状态 -->
            <ChatPanel 
              ref="chatPanel"
              :loading="isProcessingAudio"
              @message-added="handleMessageAdded"
              @messages-cleared="handleMessagesCleared"
              v-show="activeTab === 'chat'"
            />
            
            <!-- 对话模式 -->
            <div v-if="activeTab === 'chat'">
              <form id="chat-form" @submit.prevent="sendChatMessage">
                <div class="input-group mt-3">
                  <textarea class="form-control" id="chat-message" rows="3" placeholder="输入您想对数字人说的话..." v-model="chatText"></textarea>
                  <button class="btn btn-primary" type="submit" :disabled="!isConnected">
                    <i class="bi bi-send"></i> 发送
                  </button>
                </div>
              </form>
              
              <!-- 持续收音按钮 -->
              <div class="voice-record-btn" id="voice-record-btn" @click="toggleVoiceRecording">
                <i class="bi bi-mic-fill"></i>
              </div>
              <div class="voice-record-label" id="voice-record-label">{{ voiceRecordLabel }}</div>
            </div>
            
            <!-- 朗读模式 -->
              <div v-else-if="activeTab === 'tts'">
                <form id="echo-form" @submit.prevent="sendTTSMessage">
                  <div class="mb-3">
                    <label for="message" class="form-label">输入要朗读的文本</label>
                    <textarea class="form-control tts-textarea" id="message" rows="6" placeholder="输入您想让数字人朗读的文字..." v-model="ttsText"></textarea>
                  </div>
                  <button type="submit" class="btn btn-primary w-100" :disabled="!isConnected">
                    <i class="bi bi-volume-up"></i> 朗读文本
                  </button>
                </form>
              </div>
              

          </div>
        </div>
      </div>
    </div>

    <div class="footer">
      <p>Made with ❤️ by Marstaos | Frontend & Performance Optimization</p>
    </div>
    </div>
  </div>
  
  <!-- WebRTC连接组件 -->
  <WebRTCConnection ref="webrtcConnectionRef" @connection-status-change="handleConnectionStatusChange" @error="handleWebRTCError" />
  
  <!-- 隐藏的会话ID -->
  <input type="hidden" id="sessionid" v-model="sessionId">
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
import WebRTCService from './services/WebRTCService.js'
import AudioService from './services/AudioService.js'
import ChatPanel from './components/ChatPanel.vue'
import ConfigManager from './components/ConfigManager.vue'
import WebRTCConnection from './components/WebRTCConnection.vue'
import axios from 'axios'

// Vue组件引用
const chatPanel = ref(null)
const configManagerRef = ref(null)
const webrtcConnectionRef = ref(null)

// Vue响应式数据
const isProcessingAudio = ref(false)
const isConnected = ref(false)
const isConnecting = ref(false)
const isRecording = ref(false)
const statusClass = ref('status-disconnected')
const statusText = ref('未连接')
const videoSize = ref(process.env.VIDEO_CONFIG.DEFAULT_SIZE_PERCENTAGE) // 从全局配置获取默认视频大小
const activeTab = ref('chat')
const chatText = ref('')
const ttsText = ref('')
const sessionId = ref('0')
const voiceRecordLabel = ref('点击启用麦克风')
const sidebarOpen = ref(false) // 侧边栏显示状态
const useStunServer = ref(false) // STUN服务器选择状态

// 音频服务相关
let mediaRecorder;
let audioChunks = [];
let isMicEnabled = false;
let audioStream = null;
let audioContext = null;
let analyser = null;
let dataArray = null;
let soundDetectionInterval = null;
let silenceTimeout = null;

// 从全局配置获取参数
const { SOUND_THRESHOLD, CHECK_INTERVAL_MS, SILENCE_TIMEOUT_MS } = process.env.AUDIO_CONFIG;
const { DEFAULT_SESSION_ID } = process.env.SESSION_CONFIG;

// 生命周期钩子
onMounted(() => {
  console.log('LiveTalking应用已启动')
  
  // 设置连接状态变化回调
  WebRTCService.setOnConnectionStatusChange((status) => {
    handleConnectionStatusChange(status)
  })
  
  // 自动请求麦克风权限
  requestMicrophonePermission()
})

// 切换到对话模式 - 保持向后兼容
function switchToChatMode() {
  activeTab.value = 'chat'
}

// 切换到朗读模式 - 保持向后兼容
function switchToTTSMode() {
  activeTab.value = 'tts'
}

// 切换侧边栏显示/隐藏
function toggleSidebar() {
  const wasOpen = sidebarOpen.value
  sidebarOpen.value = !sidebarOpen.value
  // 当侧边栏从关闭状态变为打开状态时，请求配置信息
  if (!wasOpen && sidebarOpen.value) {
    // 给DOM更新一点时间，确保组件已经渲染
    setTimeout(() => {
      if (configManagerRef.value) {
        configManagerRef.value.loadModelConfig()
      }
    }, 100)
  }
}

onUnmounted(() => {
  // 页面卸载时清理资源
  cleanupResources()
})

// 监听视频大小变化
watch(videoSize, (newSize) => {
  const video = document.getElementById('video')
  const videoContainer = document.querySelector('.video-container')
  
  if (video && videoContainer) {
    // 计算基础容器高度 (基于原始视频大小比例)
    const baseWidth = video.videoWidth || 1920; // 默认宽度，确保有值
    const baseHeight = video.videoHeight || 1080; // 默认高度，确保有值
    const aspectRatio = baseHeight / baseWidth;
    
    // 计算新的容器高度
    const containerWidth = videoContainer.clientWidth;
    const newContainerHeight = containerWidth * aspectRatio * (newSize / 100);
    
    // 设置视频大小
    video.style.width = newSize + '%'
    video.style.height = 'auto' // 保持视频比例
    
    // 设置容器大小 - 确保容器大小与视频大小一致
    videoContainer.style.height = newContainerHeight + 'px';
    
    // 更新显示的视频大小值
    const sizeValueElement = document.getElementById('video-size-value')
    if (sizeValueElement) {
      sizeValueElement.textContent = newSize + '%'
    }
  }
})

// 请求麦克风权限
function requestMicrophonePermission() {
  navigator.mediaDevices.getUserMedia({ audio: true })
    .then(function(stream) {
      console.log('麦克风权限已获取，准备开始声音检测')
      audioStream = stream
    })
    .catch((err) => {
      console.error(`获取麦克风权限失败: ${err.name}: ${err.message}`)
      voiceRecordLabel.value = '麦克风权限被拒绝'
    })
}

// 处理WebRTC连接状态变化
function handleConnectionStatusChange(status) {
  isConnecting.value = status === 'connecting' || status === 'checking'
  isConnected.value = status === 'connected'
  
  // 更新状态样式和文本
  if (status === 'connected') {
    statusClass.value = 'status-connected'
    statusText.value = '已连接'
    // chatPanel.value?.addSystemMessage('已成功连接到数字人服务器，可以开始对话了。')
  } else if (status === 'disconnected') {
    statusClass.value = 'status-disconnected'
    statusText.value = '未连接'
    chatPanel.value?.addSystemMessage('已断开与数字人服务器的连接。')
  } else if (status === 'connecting' || status === 'checking') {
    statusClass.value = 'status-connecting'
    statusText.value = '连接中...'
  } else if (status === 'failed') {
    statusClass.value = 'status-disconnected'
    statusText.value = '连接失败'
    chatPanel.value?.addSystemMessage('连接失败，请检查网络后重试。')
  }
}

// 处理STUN服务器选择变化
function handleStunChange() {
  console.log('STUN服务器选择状态:', useStunServer.value)
  // 设置WebRTC服务是否使用STUN服务器
  WebRTCService.setUseStun(useStunServer.value)
}

// 开始连接
function startConnection() {
  isConnecting.value = true
  // 根据STUN选择状态设置WebRTC配置
  WebRTCService.setUseStun(useStunServer.value)
  WebRTCService.createConnection().catch(error => {
    console.error('WebRTC连接失败:', error)
    isConnecting.value = false
    handleConnectionStatusChange('disconnected')
  })
  
  // 添加定时器检查视频流是否已加载
  let connectionCheckTimer = setInterval(function() {
    const video = document.getElementById('video')
    // 检查视频是否有数据
    if (video.readyState >= 3 && video.videoWidth > 0) {
      handleConnectionStatusChange('connected')
      // 连接成功后，从WebRTCService获取会话ID并更新
      const newSessionId = WebRTCService.getSessionId();
      if (newSessionId && newSessionId !== '0') {
        sessionId.value = newSessionId;
        console.log('Session ID updated to:', sessionId.value);
      }
      clearInterval(connectionCheckTimer)
    }
  }, process.env.SESSION_CONFIG.WEBRTC_STATE_CHECK_INTERVAL_MS); // 从全局配置获取检查间隔
  
  // 设置连接超时时间
  setTimeout(function() {
    if (connectionCheckTimer) {
      clearInterval(connectionCheckTimer)
    }
  }, process.env.SESSION_CONFIG.WEBRTC_CONNECTION_TIMEOUT_MS) // 从全局配置获取超时时间
}

// 监听WebRTC连接事件，更新会话ID
window.onWebRTCConnected = function() {
  setTimeout(() => {
    const newSessionId = WebRTCService.getSessionId();
    if (newSessionId && newSessionId !== '0') {
      sessionId.value = newSessionId;
      console.log('Session ID updated via WebRTC event:', sessionId.value);
    }
  }, 500);
}

// 停止连接
function stopConnection() {
  WebRTCService.closeConnection()
  handleConnectionStatusChange('disconnected')
}

// 处理WebRTC错误
function handleWebRTCError(error) {
  console.error('WebRTC错误:', error)
  // 可以在这里添加错误提示逻辑，比如显示通知
}

// 切换录制状态
function toggleRecording() {
  if (isRecording.value) {
    stopRecording()
  } else {
    startRecording()
  }
}

// 开始录制
function startRecording() {
  console.log('Starting recording...')
  isRecording.value = true
  
  // 获取当前会话ID，确保使用有效的值
  const currentSessionId = sessionId.value || process.env.SESSION_CONFIG.DEFAULT_SESSION_ID;
  console.log('Using session ID:', currentSessionId);
  
  // 创建getUrl函数
  const getUrl = new Function(`return ${process.env.API_CONFIG.getUrl}`)();
  
  fetch(getUrl('record'), {
    body: JSON.stringify({
      type: 'start_record',
      sessionid: currentSessionId, // 使用字符串格式而不是转换为数字
    }),
    headers: {
      'Content-Type': 'application/json'
    },
    method: 'POST'
  }).then(function(response) {
    if (response.ok) {
      console.log('Recording started.')
      const recordingIndicator = document.getElementById('recording-indicator')
      if (recordingIndicator) {
        recordingIndicator.classList.add('active')
      }
    } else {
      // 获取更详细的错误信息
      response.text().then(errorText => {
        console.error('Failed to start recording. Status:', response.status, 'Message:', errorText)
        isRecording.value = false
      })
    }
  }).catch(function(error) {
    console.error('Error starting recording:', error)
    isRecording.value = false
  })
}

// 录制文件URL引用
const recordingFileUrl = ref('')
const downloadError = ref('')
const isDownloading = ref(false)

// 停止录制
function stopRecording() {
  console.log('Stopping recording...')
  downloadError.value = ''
  
  // 获取当前会话ID，确保使用有效的值
  const currentSessionId = sessionId.value || process.env.SESSION_CONFIG.DEFAULT_SESSION_ID;
  console.log('Using session ID:', currentSessionId);
  
  // 直接设置新的下载路由URL为主要尝试的URL
  const downloadRecordingUrl = `${process.env.API_CONFIG.baseUrl}/download_recording?sessionid=${currentSessionId}`;
  recordingFileUrl.value = downloadRecordingUrl;
  console.log('Using optimized recording file URL:', recordingFileUrl.value);
  
  // 创建getUrl函数
  const getUrl = new Function(`return ${process.env.API_CONFIG.getUrl}`)();
  
  fetch(getUrl('record'), {
    body: JSON.stringify({
      type: 'end_record',
      sessionid: currentSessionId, // 使用字符串格式而不是转换为数字
    }),
    headers: {
      'Content-Type': 'application/json'
    },
    method: 'POST'
  }).then(function(response) {
    if (response.ok) {
      // 尝试解析响应为JSON
      return response.text().then(text => {
        try {
          return JSON.parse(text);
        } catch (e) {
          console.warn('响应不是有效的JSON格式:', text);
          return { rawResponse: text };
        }
      }).then(data => {
        console.log('Recording stopped. Data:', data)
        isRecording.value = false
        
        // 更新录制指示器
        const recordingIndicator = document.getElementById('recording-indicator')
        if (recordingIndicator) {
          recordingIndicator.classList.remove('active')
        }
      })
    } else {
      // 获取更详细的错误信息
      response.text().then(errorText => {
        console.error('Failed to stop recording. Status:', response.status, 'Message:', errorText)
        isRecording.value = false
        
        // 更新录制指示器
        const recordingIndicator = document.getElementById('recording-indicator')
        if (recordingIndicator) {
          recordingIndicator.classList.remove('active')
        }
        
        downloadError.value = `停止录制失败: ${response.status} ${errorText}`
        
        // 提供优化后的后备下载链接，使用新的下载路由格式
        const timestamp = new Date().getTime();
        recordingFileUrl.value = `${process.env.API_CONFIG.baseUrl}/download_recording?sessionid=${currentSessionId}&timestamp=${timestamp}&fallback=true`
        console.log('Providing fallback recording file URL:', recordingFileUrl.value)
      })
    }
  }).catch(function(error) {
    console.error('Error stopping recording:', error)
    isRecording.value = false
    
    // 更新录制指示器
    const recordingIndicator = document.getElementById('recording-indicator')
    if (recordingIndicator) {
      recordingIndicator.classList.remove('active')
    }
    
    downloadError.value = `停止录制时发生错误: ${error.message}`
    
    // 提供优化后的后备下载链接，使用新的下载路由格式
    const timestamp = new Date().getTime();
    recordingFileUrl.value = `${process.env.API_CONFIG.baseUrl}/download_recording?sessionid=${currentSessionId}&timestamp=${timestamp}&fallback=true`
    console.log('Providing fallback recording file URL due to exception:', recordingFileUrl.value)
  })
}

// 下载录制文件
function downloadRecording() {
  if (!recordingFileUrl.value) {
    console.error('No recording file to download')
    downloadError.value = '没有可下载的录制文件'
    return
  }
  
  // 重置错误状态
  downloadError.value = ''
  isDownloading.value = true
  
  try {
    console.log('Attempting to download recording:', recordingFileUrl.value)
    
    // 直接使用新的下载路由格式进行下载
    createAndTriggerDownloadLink(recordingFileUrl.value)
    
  } catch (error) {
    console.error('Error initiating download:', error)
    handleDownloadError(`开始下载时发生错误: ${error.message}`)
  }
}


// 创建并触发下载链接
function createAndTriggerDownloadLink(url) {
  try {
    const link = document.createElement('a')
    link.href = url
    // 设置文件名（假设文件名基于会话ID和时间戳）
    link.download = `recording_${sessionId.value || 'unknown'}_${new Date().getTime()}.mp4`
    document.body.appendChild(link)
    
    // 添加点击事件监听以捕获错误
    link.addEventListener('error', (e) => {
      console.error('Error in download link:', e)
      handleDownloadError('下载链接创建失败，请尝试使用备用下载方式')
      // 备用方案：直接在新标签页打开下载链接
      window.open(url, '_blank')
    })
    
    // 触发下载
    link.click()
    
    // 延迟移除链接元素，确保下载有足够时间开始
    setTimeout(() => {
      if (link.parentNode) {
        document.body.removeChild(link)
      }
      isDownloading.value = false
    }, 2000) // 延长延迟时间以确保下载完成
    
    console.log('Recording file download started:', url)
  } catch (error) {
    console.error('Error creating download link:', error)
    handleDownloadError(`创建下载链接时发生错误: ${error.message}`)
  }
}

// 处理下载错误
function handleDownloadError(message) {
  console.error('Download error:', message)
  downloadError.value = message
  isDownloading.value = false
  
  // 尝试备用方案：直接在新标签页打开下载链接
  if (recordingFileUrl.value) {
    console.log('Opening recording URL in new tab as fallback')
    setTimeout(() => {
      window.open(recordingFileUrl.value, '_blank')
    }, 500) // 延迟打开，以便用户看到错误信息
  }
}

// 发送聊天消息
function sendChatMessage() {
  const message = chatText.value.trim()
  if (!message) return
  
  console.log('Sending chat message:', message)
  
  // 添加用户消息到聊天面板
  chatPanel.value?.addUserMessage(message)
  chatText.value = ''
  
  // 获取会话ID
  const currentSessionId = WebRTCService.getSessionId() || process.env.SESSION_CONFIG.DEFAULT_SESSION_ID
  
  // 使用正确的方式获取getUrl函数
  const getUrl = new Function(`return ${process.env.API_CONFIG.getUrl}`)();
  
  // 发送消息到服务器
  fetch(getUrl('human'), {
    body: JSON.stringify({
      text: message,
      type: 'chat',
      interrupt: true,
      sessionid: parseInt(currentSessionId),
    }),
    headers: {
      'Content-Type': 'application/json'
    },
    method: 'POST'
  }).then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok')
    }
    return response.json()
  })
  .then(data => {
    if (data.code == 0) {
      chatPanel.value?.addSystemMessage(data.llm_result)
    }
  })
  .catch(error => {
    console.error('发送聊天数据时出错:', error)
  })
}

// 发送TTS消息
function sendTTSMessage() {
  const message = ttsText.value.trim()
  if (!message) return
  
  console.log('Sending TTS message:', message)
  
  // 获取会话ID
  const currentSessionId = WebRTCService.getSessionId() || process.env.SESSION_CONFIG.DEFAULT_SESSION_ID
  
  // 使用正确的方式获取getUrl函数
  const getUrl = new Function(`return ${process.env.API_CONFIG.getUrl}`)();
  
  // 发送消息到服务器
  fetch(getUrl('human'), {
    body: JSON.stringify({
      text: message,
      type: 'echo',
      interrupt: true,
      sessionid: parseInt(currentSessionId),
    }),
    headers: {
      'Content-Type': 'application/json'
    },
    method: 'POST'
  })
  
  ttsText.value = ''
  chatPanel.value?.addSystemMessage(`已发送朗读请求: "${message}"`, 'system')
}

// 切换语音录制状态
function toggleVoiceRecording() {
  if (isMicEnabled) {
    disableMicrophone()
  } else {
    enableMicrophone()
  }
}

// 启用麦克风并开始声音检测
function enableMicrophone() {
  if (isMicEnabled) return
  
  if (!audioStream) {
    // 如果之前没有获取到音频流，重新获取
    navigator.mediaDevices.getUserMedia({ audio: true })
      .then(function(stream) {
        audioStream = stream
        setupAudioAnalysis()
        startSoundDetection()
      })
      .catch((err) => {
        console.error(`获取麦克风权限失败: ${err.name}: ${err.message}`)
      })
  } else {
    setupAudioAnalysis()
    startSoundDetection()
  }
}

// 禁用麦克风并停止所有处理
function disableMicrophone() {
  if (!isMicEnabled) return
  
  // 停止录音
  if (isRecording.value) {
    stopVoiceRecording()
  }
  
  // 清除定时器
  if (soundDetectionInterval) {
    clearInterval(soundDetectionInterval)
    soundDetectionInterval = null
  }
  
  if (silenceTimeout) {
    clearTimeout(silenceTimeout)
    silenceTimeout = null
  }
  
  // 关闭音频上下文
  if (audioContext) {
    audioContext.close()
    audioContext = null
    analyser = null
    dataArray = null
  }
  
  isMicEnabled = false
  
  // 更新按钮状态
  const voiceRecordBtn = document.getElementById('voice-record-btn')
  if (voiceRecordBtn) {
    voiceRecordBtn.classList.remove('recording-pulse')
    voiceRecordBtn.style.backgroundColor = ''
  }
  voiceRecordLabel.value = '点击启用麦克风'
  
  console.log('麦克风已禁用')
}

// 设置音频分析器
function setupAudioAnalysis() {
  if (!audioStream || audioContext) return
  
  // 创建音频上下文
  audioContext = new (window.AudioContext || window.webkitAudioContext)()
  
  // 创建音频源
  const source = audioContext.createMediaStreamSource(audioStream)
  
  // 创建分析器
  analyser = audioContext.createAnalyser()
  analyser.fftSize = 256
  
  // 创建数据数组
  const bufferLength = analyser.frequencyBinCount
  dataArray = new Uint8Array(bufferLength)
  
  // 连接音频节点
  source.connect(analyser)
}

// 开始声音检测
function startSoundDetection() {
  isMicEnabled = true
  
  // 更新按钮状态
  voiceRecordLabel.value = '麦克风就绪，等待声音...'
  
  console.log('开始声音检测...')
  
  // 设置声音检测定时器
  if (!soundDetectionInterval) {
    soundDetectionInterval = setInterval(checkSoundLevel, process.env.AUDIO_CONFIG.CHECK_INTERVAL_MS)
  }
}

// 检查声音级别
function checkSoundLevel() {
  if (!analyser || !dataArray) return
  
  // 获取音频数据
  analyser.getByteFrequencyData(dataArray)
  
  // 计算平均音量
  let sum = 0
  for (let i = 0; i < dataArray.length; i++) {
    sum += dataArray[i]
  }
  const average = sum / dataArray.length
  const normalizedLevel = average / 255
  
  // 检查是否检测到声音
  if (normalizedLevel > process.env.AUDIO_CONFIG.SOUND_THRESHOLD) {
    console.log('检测到声音，音量级别:', normalizedLevel)
    
    // 如果正在录音，重置静默超时
    if (isRecording.value) {
      if (silenceTimeout) {
        clearTimeout(silenceTimeout)
        silenceTimeout = null
      }
      
      // 设置新的静默超时
      silenceTimeout = setTimeout(function() {
        console.log('静默超时，结束录音')
        stopVoiceRecording()
      }, process.env.AUDIO_CONFIG.SILENCE_TIMEOUT_MS)
    } else {
      // 如果没有在录音，开始录音
      startVoiceRecording()
    }
  }
  // 额外的逻辑：当正在录音且音量低于阈值时，不立即停止，而是通过静默超时来控制
}

// 开始语音录音
function startVoiceRecording() {
  if (isRecording.value || !audioStream) return
  
  audioChunks = []
  mediaRecorder = new MediaRecorder(audioStream)
  
  mediaRecorder.ondataavailable = function(e) {
    if (e.data.size > 0) {
      audioChunks.push(e.data)
    }
  }
  
  // 设置录音停止事件
  mediaRecorder.onstop = function() {
    if (audioChunks.length > 0) {
      sendAudioData()
    }
    
    // 更新状态
    voiceRecordLabel.value = '麦克风就绪，等待声音...'
    
    console.log('录音已停止')
  }
  
  // 开始录音
  mediaRecorder.start(100) // 每100ms生成一个数据块，提高灵敏度
  isRecording.value = true
  
  // 更新按钮状态
  const voiceRecordBtn = document.getElementById('voice-record-btn')
  if (voiceRecordBtn) {
    voiceRecordBtn.classList.add('recording-pulse')
    voiceRecordBtn.style.backgroundColor = '#dc3545'
  }
  voiceRecordLabel.value = '正在录音...'
  
  console.log('开始录音...')
  
  // 设置静默超时
  if (silenceTimeout) {
    clearTimeout(silenceTimeout)
  }
  
  silenceTimeout = setTimeout(function() {
    console.log('静默超时，结束录音')
    stopVoiceRecording()
  }, SILENCE_TIMEOUT_MS)
}

// 停止语音录音
function stopVoiceRecording() {
  if (!isRecording.value) return
  
  // 清除静默超时
  if (silenceTimeout) {
    clearTimeout(silenceTimeout)
    silenceTimeout = null
  }
  
  // 确保mediaRecorder存在再调用stop方法
  if (mediaRecorder) {
    mediaRecorder.stop()
  }
  
  isRecording.value = false
  
  console.log('停止录音...')
}

// 发送音频数据
function sendAudioData() {
  // 检查是否已建立WebRTC连接
  if (!isConnected.value) {
    console.error('未建立连接，请先点击"开始连接"按钮')
    chatPanel.value?.addSystemMessage('未建立连接，请先点击"开始连接"按钮')
    isProcessingAudio.value = false
    return
  }
  
  isProcessingAudio.value = true
  
  if (audioChunks.length === 0) {
    isProcessingAudio.value = false
    return
  }
  
  // 创建音频Blob
  const audioBlob = new Blob(audioChunks, { type: 'audio/wav' })
  
  const formData = new FormData()
  formData.append('audio', audioBlob, 'recording.wav')
  formData.append('type', 'chat')
  formData.append('interrupt', 'true')
  // 使用WebRTCService获取的sessionId，与其他请求保持一致
  const currentSessionId = WebRTCService.getSessionId() || process.env.SESSION_CONFIG.DEFAULT_SESSION_ID
  // 修改：直接使用字符串格式的sessionId，不转换为整数
  formData.append('sessionid', currentSessionId)
  
  // 清空当前的音频块
  audioChunks = []
  
  // 创建getUrl函数
  const getUrl = new Function(`return ${process.env.API_CONFIG.getUrl}`)();
  
  // 发送音频数据
  fetch(getUrl('human'), {
    method: 'POST',
    body: formData
  })
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok')
    }
    return response.json()
  })
  .then(data => {
    console.log('音频数据发送成功', data)
    if (data.code == 0) {
      // 调用 addChatMessage 函数显示返回的文本
      chatPanel.value?.addUserMessage(data.data)
      chatPanel.value?.addSystemMessage(data.llm_result)
    }
  })
  .catch(error => {
    console.error('发送音频数据时出错:', error)
  })
  .finally(() => {
    isProcessingAudio.value = false
  })
}

// 处理新消息添加
function handleMessageAdded(message) {
  console.log('新消息添加:', message)
}

// 处理消息清空
function handleMessagesCleared() {
  console.log('消息已清空')
}

// 清理资源
function cleanupResources() {
  console.log('清理应用资源...')
  
  // 停止WebRTC连接
  WebRTCService.closeConnection()
  
  // 停止音频录制和处理
  disableMicrophone()
}

// 复制会话信息到剪贴板
function copySessionInfo() {
  const currentSessionId = sessionId.value || process.env.SESSION_CONFIG.DEFAULT_SESSION_ID
  const timestamp = new Date().getTime()
  const apiBaseUrl = process.env.API_CONFIG.baseUrl
  
  const sessionInfo = `会话ID: ${currentSessionId}
时间戳: ${timestamp}
基础URL: ${apiBaseUrl}
日期: ${new Date().toLocaleString()}`
  
  // 使用现代的剪贴板API
  if (navigator.clipboard && window.isSecureContext) {
    navigator.clipboard.writeText(sessionInfo).then(() => {
      // 显示临时成功提示
      const originalError = downloadError.value
      downloadError.value = '会话信息已复制到剪贴板'
      setTimeout(() => {
        downloadError.value = originalError
      }, 2000)
    }).catch(err => {
      console.error('无法复制会话信息:', err)
    })
  } else {
    // 降级方案：创建临时文本区域
    const textArea = document.createElement('textarea')
    textArea.value = sessionInfo
    textArea.style.position = 'fixed'
    textArea.style.left = '-999999px'
    textArea.style.top = '-999999px'
    document.body.appendChild(textArea)
    textArea.focus()
    textArea.select()
    
    try {
      document.execCommand('copy')
      // 显示临时成功提示
      const originalError = downloadError.value
      downloadError.value = '会话信息已复制到剪贴板'
      setTimeout(() => {
        downloadError.value = originalError
      }, 2000)
    } catch (err) {
      console.error('无法复制会话信息:', err)
    }
    
    document.body.removeChild(textArea)
  }
}
</script>

<style scoped>
/* 主容器样式 */
.dashboard-container {
  padding: 0;
  margin: 0;
  font-family: 'Microsoft YaHei', sans-serif;
  min-height: 100vh;
  display: flex;
  position: relative;
}

/* 侧边栏开关按钮 */
.sidebar-toggle-btn {
  position: fixed;
  top: 15px;
  left: 15px;
  z-index: 1000;
  border-radius: 50%;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  transition: all 0.3s ease;
}

.sidebar-toggle-btn:hover {
  transform: scale(1.05);
}

.sidebar-toggle-btn.open {
  left: 315px;
}

/* 配置管理侧边栏 */
.config-sidebar {
  position: fixed;
  top: 0;
  left: -300px;
  width: 300px;
  height: 100vh;
  background-color: #ffffff;
  box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
  z-index: 999;
  transition: all 0.3s ease;
  overflow-y: auto;
}

.config-sidebar.open {
  left: 0;
}

.sidebar-header {
  padding: 1rem;
  background-color: #f8f9fa;
  border-bottom: 1px solid #dee2e6;
}

.sidebar-header h3 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  color: #1a1a2e;
}

.sidebar-content {
  padding: 1rem;
}

/* 主内容区域 */
.main-content {
  flex: 1;
  transition: all 0.3s ease;
  padding: 20px;
  max-width: 1400px;
  margin: 0 auto;
}

.main-content.sidebar-open {
  margin-left: 300px;
}

/* 页头标题样式 */
.dashboard-container h1 {
  font-size: 2.5rem;
  font-weight: bold;
  color: #1a1a2e;
  margin-bottom: 1rem;
}

/* 状态指示器样式 */
.status-indicator {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  margin-right: 8px;
  vertical-align: middle;
}

.status-connected {
  background-color: #28a745;
}

.status-connecting {
  background-color: #ffc107;
  animation: pulse 1.5s infinite;
}

.status-disconnected {
  background-color: #dc3545;
}

/* 视频容器样式 */
.video-container {
  position: relative;
  width: 100%;
  background-color: #1a1a2e;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-top-left-radius: 0.375rem;
  border-top-right-radius: 0.375rem;
  transition: height 0.3s ease;
  min-height: 100px; /* 设置最小高度以确保容器始终可见 */
}

.video-container video {
  width: 100%;
  height: auto;
  object-fit: contain;
  transition: all 0.3s ease;
}

/* 录制指示器样式 */
.recording-indicator {
  position: absolute;
  top: 20px;
  right: 20px;
  background-color: rgba(220, 53, 69, 0.95);
  color: white;
  padding: 8px 16px;
  border-radius: 20px;
  display: none;
  align-items: center;
  font-weight: 600;
  z-index: 10;
}

.recording-indicator.active {
  display: flex;
  animation: fadeIn 0.3s ease;
}

.recording-indicator .blink {
  width: 10px;
  height: 10px;
  background-color: white;
  border-radius: 50%;
  margin-right: 10px;
  animation: blink 1s infinite;
}

/* 控制面板样式 */
.controls-container {
  padding: 1.5rem;
  background-color: #f8f9fa;
  border-top: 1px solid #dee2e6;
}

/* 视频大小控制样式 */
.video-size-control {
  margin-top: 1rem;
}

.video-size-control label {
  font-weight: 600;
  color: #495057;
}

/* 语音录制按钮样式 */
.voice-record-btn {
  position: fixed;
  bottom: 30px;
  right: 30px;
  width: 70px;
  height: 70px;
  border-radius: 50%;
  background-color: #007bff;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 15px rgba(0, 123, 255, 0.4);
  cursor: pointer;
  z-index: 1000;
  transition: all 0.3s ease;
  font-size: 1.5rem;
}

.voice-record-btn:hover {
  transform: scale(1.1);
  box-shadow: 0 6px 20px rgba(0, 123, 255, 0.6);
}

.voice-record-btn.recording-pulse {
  background-color: #dc3545 !important;
  animation: pulse 1.5s infinite;
}

.voice-record-label {
  position: fixed;
  bottom: 110px;
  right: 30px;
  background-color: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 0.9rem;
  z-index: 1000;
  min-width: 200px;
  text-align: center;
}

/* 页脚样式 */
.footer {
  text-align: center;
  padding: 2rem;
  margin-top: 2rem;
  color: #6c757d;
  font-size: 0.9rem;
  border-top: 1px solid #dee2e6;
}

/* 动画效果 */
@keyframes blink {
  0% { opacity: 1; }
  50% { opacity: 0.5; }
  100% { opacity: 1; }
}

@keyframes pulse {
  0% { transform: scale(1); box-shadow: 0 4px 15px rgba(220, 53, 69, 0.4); }
  50% { transform: scale(1.05); box-shadow: 0 6px 20px rgba(220, 53, 69, 0.6); }
  100% { transform: scale(1); box-shadow: 0 4px 15px rgba(220, 53, 69, 0.4); }
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* TTS文本区域样式 */
.tts-textarea {
  max-height: 250px; /* 限制最大高度，防止无限延伸 */
  overflow-y: auto;
  resize: vertical; /* 允许垂直调整大小 */
}

.tts-textarea::-webkit-scrollbar {
  width: 6px;
}

.tts-textarea::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.tts-textarea::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
  transition: background 0.3s;
}

.tts-textarea::-webkit-scrollbar-thumb:hover {
  background: #a8a8a8;
}

/* 响应式调整 - 侧边栏在小屏幕设备上的处理 */
@media (max-width: 768px) {
  /* 侧边栏调整 */
  .config-sidebar {
    width: 280px;
    left: -280px;
  }
  
  .config-sidebar.open {
    left: 0;
  }
  
  .main-content.sidebar-open {
    margin-left: 0;
    opacity: 0.5;
  }
  
  .sidebar-toggle-btn.open {
    left: 295px;
  }
  
  /* 调整按钮大小 */
  .sidebar-toggle-btn {
    width: 35px;
    height: 35px;
    top: 10px;
    left: 10px;
  }
  
  /* 主内容区域调整 */
  .main-content {
    padding: 10px;
  }
}

@media (max-width: 992px) {
  .dashboard-container h1 {
    font-size: 2rem;
  }
  
  .voice-record-btn {
    width: 60px;
    height: 60px;
    font-size: 1.2rem;
    bottom: 20px;
    right: 20px;
  }
  
  .voice-record-label {
    bottom: 90px;
    right: 20px;
    min-width: 150px;
    font-size: 0.8rem;
  }
}

@media (max-width: 768px) {
  .dashboard-container {
    padding: 10px;
  }
  
  .dashboard-container h1 {
    font-size: 1.75rem;
  }
  
  .controls-container {
    padding: 1rem;
  }
}

@media (max-width: 576px) {
  .dashboard-container h1 {
    font-size: 1.5rem;
  }
  
  .voice-record-btn {
    width: 50px;
    height: 50px;
    font-size: 1rem;
  }
  
  .voice-record-label {
    display: none;
  }
}
</style>